package com.leyou.order.service;

import com.leyou.client.UserClient;
import com.leyou.common.enums.ExceptionEnum;
import com.leyou.common.exceptions.LyException;
import com.leyou.common.threadlocals.UserHolder;
import com.leyou.common.utils.BeanHelper;
import com.leyou.common.utils.IdWorker;
import com.leyou.dto.AddressDTO;
import com.leyou.item.client.ItemClient;
import com.leyou.item.dto.SkuDTO;
import com.leyou.order.dto.CartDTO;
import com.leyou.order.dto.OrderDTO;
import com.leyou.order.entity.Order;
import com.leyou.order.entity.OrderDetail;
import com.leyou.order.entity.OrderLogistics;
import com.leyou.order.enums.OrderStatusEnum;
import com.leyou.order.mapper.OrderDetailMapper;
import com.leyou.order.mapper.OrderLogisticsMapper;
import com.leyou.order.mapper.OrderMapper;
import com.leyou.order.utils.PayHelper;
import com.leyou.order.vo.OrderDetailVO;
import com.leyou.order.vo.OrderLogisticsVO;
import com.leyou.order.vo.OrderVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import tk.mybatis.mapper.entity.Example;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author Eric
 * @version v1.0
 * @package com.leyou.order.service
 * @date 2019/7/13 16:5r0
 * @description:
 **/
@Service
@Slf4j
public class OrderService {

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private OrderDetailMapper orderDetailMapper;

    @Autowired
    private OrderLogisticsMapper orderLogisticsMapper;

    @Autowired
    private UserClient userClient;

    @Autowired
    private IdWorker idWorker;

    @Autowired
    private ItemClient itemClient;


    @Transactional
    public Long createOrder(OrderDTO orderDTO) {

        // 1 写order
        Order order = new Order();

        // 1.1 订单编号
        long orderId = idWorker.nextId();
        order.setOrderId(orderId);

        // 1.2 登录用户
        Long userId = UserHolder.getUser();
        order.setUserId(userId);

        // 1.3 金额相关信息
        List<CartDTO> carts = orderDTO.getCarts();
        // 获取所有sku的id
        List<Long> idList = carts.stream().map(CartDTO::getSkuId).collect(Collectors.toList());
        // 处理CartDTO为一个map， 其key是skuId；值是num
        Map<Long, Integer> numMap = carts.stream().collect(Collectors.toMap(CartDTO::getSkuId, CartDTO::getNum));
        // 1.3.1 查询sku
        List<SkuDTO> skuList = itemClient.querySkuByIds(idList);
        // 定义一个OrderDetail的集合
        List<OrderDetail> details = new ArrayList<>();
        // 1.3.2 计算金额的和
        long total = 0;
        for (SkuDTO sku : skuList) {
            int num = numMap.get(sku.getId());
            // 计算总金额
            total += sku.getPrice() * num;
            // 组装OrderDetail
            OrderDetail detail = new OrderDetail();
            detail.setOrderId(orderId);
            detail.setImage(StringUtils.substringBefore(sku.getImages(), ","));
            detail.setNum(num);
            detail.setSkuId(sku.getId());
            detail.setOwnSpec(sku.getOwnSpec());
            detail.setPrice(sku.getPrice());
            detail.setTitle(sku.getTitle());
            details.add(detail);
        }
        // 1.3.3 填写金额数据
        order.setTotalFee(total);
        order.setPaymentType(orderDTO.getPaymentType());
        order.setPostFee(0L);
        order.setActualFee(total + order.getPostFee()/* - 优惠金额*/);

        // 1.4 订单状态初始化
        order.setStatus(OrderStatusEnum.INIT.value());

        // 1.5 写order到数据库
        int count = orderMapper.insertSelective(order);
        if(count != 1){
            throw new LyException(ExceptionEnum.INSERT_OPERATION_FAIL);
        }

        // 2 写OrderDetail
        count = orderDetailMapper.insertList(details);
        if(count != details.size()){
            throw new LyException(ExceptionEnum.INSERT_OPERATION_FAIL);
        }

        // 3 写orderLogistics
        // 3.1.查询收货地址
        AddressDTO addr = userClient.queryAddressById(userId, orderDTO.getAddressId());
        // 3.2.填写物流信息
        OrderLogistics logistics = BeanHelper.copyProperties(addr, OrderLogistics.class);
        logistics.setOrderId(orderId);

        count = orderLogisticsMapper.insertSelective(logistics);
        if(count != 1){
            throw new LyException(ExceptionEnum.INSERT_OPERATION_FAIL);
        }

        // 4 减库存
        itemClient.minusStock(numMap);

        return orderId;
    }

    public OrderVO queryOrderById(Long orderId) {

        //查询订单
        Order order = orderMapper.selectByPrimaryKey(orderId);
        if (order==null){
            throw new LyException(ExceptionEnum.ORDER_NOT_FOUND);
        }

        //查看用户是否与用户一致
        Long userId = UserHolder.getUser();
        if (!userId.equals(order.getUserId())){
            throw new LyException(ExceptionEnum.ORDER_NOT_FOUND);
        }

        //查看订单物流
        OrderLogistics orderLogistics = orderLogisticsMapper.selectByPrimaryKey(orderId);
        if (orderLogistics==null){
            throw new LyException(ExceptionEnum.ORDER_NOT_FOUND);
        }

        //查看订单详情
        OrderDetail detail = new OrderDetail();
        detail.setOrderId(orderId);
        List<OrderDetail> orderDetails = orderDetailMapper.select(detail);
        if (CollectionUtils.isEmpty(orderDetails)){
            throw new LyException(ExceptionEnum.ORDER_NOT_FOUND);
        }

        //返回订单
        OrderVO orderVO = BeanHelper.copyProperties(order, OrderVO.class);
        orderVO.setDetailList(BeanHelper.copyWithCollection(orderDetails, OrderDetailVO.class));
        orderVO.setLogistics(BeanHelper.copyProperties(orderLogistics, OrderLogisticsVO.class));

        return orderVO;

    }


    @Autowired
    private PayHelper payHelper;
    @Autowired
    private StringRedisTemplate redisTemplate;

    public String createPayUrl(Long orderId) {
        // 先看是否已经生成过：
        String key = String.format("", orderId);
        String cacheUrl = redisTemplate.opsForValue().get(key);
        if (StringUtils.isNoneBlank(cacheUrl)) {
            return cacheUrl;
        }
        // 查询订单
        Order order = orderMapper.selectByPrimaryKey(orderId);
        if(order == null){
            throw new LyException(ExceptionEnum.ORDER_NOT_FOUND);
        }
        // 判断订单状态
        Integer status = order.getStatus();
        if(!status.equals(OrderStatusEnum.INIT.value())){
            // 订单已经支付过了，订单状态异常
            throw new LyException(ExceptionEnum.INVALID_ORDER_STATUS);
        }
        // 支付金额，测试时写1
        Long actualPay = order.getTotalFee();

        // 商品描述
        String desc = "【乐优商城】商品信息";
        String url = payHelper.getPayUrl(orderId, desc,actualPay);

        // 存入redis，设置有效期为 2小时
        redisTemplate.opsForValue().set(key, url, 2, TimeUnit.HOURS);
        return url;
    }



    /**
     * 清理订单
     * @param deadline
     */
    public void closeOverdueOrders(Date deadline){
        //查询我们要清理哪些订单
        List<Long> orderIds = orderMapper.queryOverdueUnpaidOrder(deadline);
        if (CollectionUtils.isEmpty(orderIds)){
            log.info("没有需要清理的订单!");
            return;
        }

        //修改订单的status和close_time
        Order order = new Order();
        order.setCloseTime(new Date());
        order.setStatus(OrderStatusEnum.CLOSED.value());
        //添加订单更新的条件，属于清理订单的
        Example example = new Example(Order.class);
        example.createCriteria().andIn("order_id",orderIds);

        int count = orderMapper.updateByExampleSelective(order, example);
        log.info("清理订单的数量为：{}",count);
        if (count!=orderIds.size()){
            log.error("订单状态更新失败");
            throw new LyException(ExceptionEnum.UPDATE_OPERATION_FAIL);
        }

        //添加库存
        //查询哪些sku商品需要更新库存
        Example detailExample = new Example(OrderDetail.class);
        detailExample.createCriteria().andIn("order_id",orderIds);

        List<OrderDetail> orderDetails = orderDetailMapper.selectByExample(detailExample);
        if (CollectionUtils.isEmpty(orderDetails)){
            log.info("没有查询到需要清理的商品!");
        }

        //将查询信息的skuId和num分装
        Map<Long, Integer> map = orderDetails.stream().collect(Collectors.groupingBy(
                OrderDetail::getSkuId, Collectors.summingInt(OrderDetail::getNum)
        ));
        //调用添加库存方法
        itemClient.plusStock(map);


    }
}
